#pragma once

// I feel like I write one of these for every project I do.
// Stream is an abstraction for a data source, usually a file
// or a memory location. Abstracting the source into a stream
// of bytes is phenomenally useful for a number of data
// processing algorithms.
//
// The base stream class just supports seeking and telling.
// Reading and writing are separated out into other interfaces.
// This is because relatively few stream-processing applications
// need to both read and write the same stream. Separating the
// concerns this way allows individual implementations to be
// simpler.
class IStream {
public:
  // Stream implementations differ in terms of capabilities. For instance,
  // some streams (like streaming network audio, for instance)
  // don't have a defined size. Other streams don't support random
  // access.Rigorously defining the capabilities of streams makes
  // it possible to support protocol stacks made out of nested stream
  // objects.
  enum Capabilities {
    CanSeek       	= 0x01,
    CanTellPosition = 0x04,
    CanTellSize     = 0x08
  };

  enum SeekType {
    FromBeginning,
    FromEnd,
    FromCurrent
  };

  typedef unsigned long long streampos_t;
  typedef signed long long streamoffs_t;
  typedef unsigned long long streamsize_t;

  virtual streamsize_t Size() const = 0;
  virtual streamoffs_t CurrentPos() const = 0;
  virtual bool Seek(streamoffs_t offset, SeekType whence) = 0;
};

class IStreamReader : public IStream {
  virtual IStream::streamsize_t Read(IStream::streamsize_t size, char* dest) = 0;
  virtual IStreamReader* Clone() = 0;
};


